package com.dss.auto_deploy.util;

import cn.hutool.core.collection.CollectionUtil;
import com.dss.auto_deploy.config.DssProperties;
import com.dss.auto_deploy.constants.AutoConstants;
import com.dss.auto_deploy.domain.AdmRegistryTagHst;
import com.dss.auto_deploy.vo.AdmDockerVo;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.model.Container;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.api.model.PullResponseItem;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.okhttp.OkDockerHttpClient;
import com.github.dockerjava.transport.DockerHttpClient;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.Closeable;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * @Description:
 * @author: dongshoushan
 * @date: 2022年09月21日 10:59
 */
@Component
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
@Slf4j
public class DockerUtil {
    private final RemoteSshUtil remoteSshUtil;
    private final CacheUtils cacheUtils;
    private final DssProperties dssProperties;
    public DockerClient getDockerClient(String s) {
        URI url = null;
        try{
            url =new URI(s);
        }catch (Exception e){

        }
        DockerClientConfig dockerClientConfig = DefaultDockerClientConfig
                .createDefaultConfigBuilder()
                .build();
        DockerHttpClient httpClient = new OkDockerHttpClient.Builder()
                .dockerHost(url)
                .connectTimeout(dssProperties.getDockerTimeOut())
                .build();
        return DockerClientBuilder.getInstance(dockerClientConfig).withDockerHttpClient(httpClient).build();
    }

    public DockerClient getDockerClientByDocker(AdmDockerVo admDockerVo) {
        String url = StringUtils.format("tcp://{}:{}", admDockerVo.getIp(), admDockerVo.getPort());
        if (cacheUtils.hasKey(url)){
            return cacheUtils.getCacheObject(url);
        }else {
            DockerClient dockerClient = getDockerClient(url);
            cacheUtils.setCacheObject(url,dockerClient,1000*1000*1000*1000);
            return dockerClient;
        }
    }

    public void close(DockerClient dockerClient) {
        //try {
        //    if (dockerClient!=null){
        //        dockerClient.close();
        //    }
        //}catch (Exception e) {
        //    log.error(e.getMessage());
        //}
    }

    /**
     * 根据名称模糊匹配移除镜像
     *
     * @param dockerClient
     * @param imageName
     */
    public void delImageByName(DockerClient dockerClient, String imageName) {
        List<Image> imageList = getImageNameListByName(dockerClient, imageName);
        imageList.forEach(image -> {
            try {
//                FileUtils.writeDockerFileInRealTime(StringUtils.format("删除镜像 {}", image));
                dockerClient.removeImageCmd(image.getId()).withForce(true).exec();
            } catch (Exception e) {
                //log.error("删除镜像失败：{}", e.getMessage());
            }
        });
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 获取镜像，并只保留最近5个镜像
     *
     * @param dockerClient
     * @param imageName
     * @return
     */
    public List<Image> getImageNameListByName(DockerClient dockerClient, String imageName) {
        List<Image> exec = dockerClient.listImagesCmd().exec();
        List<Image> imageList = new ArrayList<>();
        exec.forEach(image -> {
            String[] repoTags = image.getRepoTags();
            if (repoTags != null) {
                Arrays.stream(repoTags).filter(repoTag -> repoTag.contains(imageName) ||repoTag.contains("<none>")).map(repoTag -> image).forEach(imageList::add);
            }
            String[] repoDigests = image.getRepoDigests();
            if (repoDigests != null) {
                Arrays.stream(repoDigests).filter(repoTag -> repoTag.contains(imageName)).map(repoTag -> image).forEach(imageList::add);
            }
        });
        if (CollectionUtil.isNotEmpty(imageList)){
            imageList.sort(Comparator.comparing(Image::getCreated).reversed());
        }
        return imageList;
    }
    public Image getImageNameByName(DockerClient dockerClient, String fullImageName) {
        List<Image> exec = dockerClient.listImagesCmd().exec();
        for (Image image : exec) {
            String[] repoTags = image.getRepoTags();
            for (String repoTag : repoTags) {
                if (repoTag.equals(fullImageName)) {
                    return image;
                }
            }
        }
        return null;
    }



    /**
     * 停止删除容器
     *
     * @param dockerClient
     * @param name
     */
    public void delContainer(DockerClient dockerClient, String name) {
        List<Container> filterList = dockerClient.listContainersCmd().withShowAll(true).exec();
        filterList.forEach(container -> {
            String[] names = container.getNames();
            String collect = Arrays.stream(names).collect(Collectors.joining(","));
            if (container.getImage().contains(name) || collect.contains(name)) {
                try {
                    if ("running".equals(container.getState()) || "restarting".equals(container.getState())) {
                        dockerClient.stopContainerCmd(container.getId()).exec();
//                        System.out.println("停止容器：" + container.getNames()[0]);
                    }
                    dockerClient.removeContainerCmd(container.getId()).withForce(true).withRemoveVolumes(true).exec();
                    System.out.println("删除容器：" + container.getNames()[0]);
                }catch (Exception e) {
                    log.error("删除容器失败：{}",e.getMessage());
                }
            }
        });
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    public void delContainerById(DockerClient dockerClient, String id) {
        List<Container> filterList = dockerClient.listContainersCmd().withShowAll(true).exec();
        filterList.stream().filter(s->id.equals(s.getId())).findFirst().ifPresent(container -> {
            try {
                if ("running".equals(container.getState()) || "restarting".equals(container.getState())) {
                    dockerClient.stopContainerCmd(container.getId()).exec();
//                        System.out.println("停止容器：" + container.getNames()[0]);
                }
                dockerClient.removeContainerCmd(container.getId()).withForce(true).withRemoveVolumes(true).exec();
//                    System.out.println("删除容器：" + container.getNames()[0]);
            }catch (Exception e) {
                log.error("删除容器失败：{}",e.getMessage());
            }
        });
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }



    /**
     * 根据名称查询镜像
     *
     * @param dockerClient
     * @param name
     * @return
     */
    public List<Container> getContainerListByNameLike(DockerClient dockerClient, String name) {
        List<Container> list = dockerClient.listContainersCmd().withShowAll(true).exec()
                .stream().filter(container -> container.getImage().contains(name)).collect(Collectors.toList());
        return list;
    }




    /**
     * 根据容器id查询
     *
     * @param containerId
     * @return
     */
    public Container getByContainerId(DockerClient dockerClient, String containerId) {
        List<Container> containerList = dockerClient.listContainersCmd().withShowAll(true).exec();
        return containerList.stream().filter(containerModel -> containerId.equals(containerModel.getId())).findFirst().orElse(null);
    }
    public List<Container> getAllContainer(DockerClient dockerClient) {
        try {
            return dockerClient.listContainersCmd().withShowAll(true).exec();
        }catch (Exception e){

        }
        return new ArrayList<>();
    }


    public void pullAndSave(DockerClient dockerClient, String imageFullName, AdmRegistryTagHst registryTagHst, String path, Session session, CountDownLatch  mainLatch) throws Exception {
        Channel channel = session.openChannel("sftp");
        channel.connect();
        ChannelSftp sftp = (ChannelSftp) channel;
        delImageByName(dockerClient, registryTagHst.getImageName());
        dockerClient.pullImageCmd(imageFullName).exec(new ResultCallback<PullResponseItem>() {

            @Override
            public void close() {

            }

            @Override
            public void onStart(Closeable closeable) {

            }

            @Override
            public void onNext(PullResponseItem object) {

            }

            @Override
            public void onError(Throwable throwable) {

            }

            @Override
            public void onComplete() {
                try {
                    String cmd = StringUtils.format(AutoConstants.SAVE_IMAGES, AutoConstants.LINUX_TEMP_PATH, registryTagHst.getImageName(), registryTagHst.getTag(), imageFullName);
                    System.out.println("执行操作：" + cmd);
                    remoteSshUtil.exec(cmd, session);
                    String fileName = StringUtils.format("{}.{}.tar", registryTagHst.getImageName(), registryTagHst.getTag());
                    FileUtils.createFilePath(new File(path));
                    remoteSshUtil.download(AutoConstants.LINUX_TEMP_PATH, fileName, path + "/" + fileName, sftp);
                    remoteSshUtil.exec(StringUtils.format("rm -rf {}/{}",AutoConstants.LINUX_TEMP_PATH,fileName), session);
                    delImageByName(dockerClient, registryTagHst.getImageName());
                    mainLatch.countDown();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }finally {
                    sftp.disconnect();
                    channel.disconnect();
                }
            }
        });
    }
}
